define(function() { //tabs
    var scope = this,
        $$ = bowlder;
    var state = scope.state = {
        events: "mouseover", //tab-nav的触发方法
        interval: 0, //定时切换间隔
        loop: true, //是否首尾循环
        slide: false,
        cursor: 0
    };
    var cls = state.cls = {
        active: "on" //激活的tab-nav, tab-body共用此class
    };
    var $root, $navs, $bodys, roles, total, _oldCursor;

    function getIndex(index){
        if(isNaN(index) && $navs && roles[index]){
            var target = roles[index][0];
            $navs.each(function(node, i){
                if(target == node) index = i;
                else if($bodys && target == $bodys[i]) index = i;
            });
        }else{
            index = parseInt(index);
        }
        return index;
    }
    state.set = function(i) {
        delete state._delayTimer;
        var index = getIndex(i);
        if(isNaN(index)){
            if(i == 'next' || i == 'prev'){
                state[i]();
            }
            return;
        }
        index = index <= 0 ? 0 : index >= total ? total - 1 : index;
        var result;
        if (scope.hasOwnProperty("onShow")) {
            result = scope.onShow(index, state.cursor);
            if (result === false) return;
        }
        scope.$emit("onshow", index, _oldCursor);

        if (index != _oldCursor) scope.$emit("onchange", index, _oldCursor);
        if (result && result.then) {
            result.then(function() {
                _show(index);
            });
        } else {
            _show(index);
        }
    }
    state.next = function() {
        var cursor = state.cursor;
        if (cursor >= total - 1 && !state.loop) return;
        state.set((cursor + 1) % total);
    };
    state.prev = function() {
        var cursor = state.cursor;
        if (cursor <= 0 && !state.loop) return;
        state.set(cursor <= 0 ? total - 1 : (cursor - 1) % total);
    };

    function _show(index) {
        if (!$navs) return;
        var ctrl = $navs.eq(index);
        // 更新当前class
        $navs.removeClass(cls.active);
        if(ctrl){
            ctrl.addClass(cls.active);
            state.ctrl = ctrl[0];
        }

        if ($bodys) {
            $bodys.removeClass(cls.active);
            var body = $bodys.eq(index);
            body && body.addClass(cls.active);
            if (state.showhide) {
                $bodys.hide();
                body && body.show();
            }
        }

        state.cursor = index;
        if (scope.hasOwnProperty("callback")) {
            scope.callback.call(scope, index);
        }
        roles["tab-nav-i"] && roles["tab-nav-i"].css({
            translateX: index*100 + '%'
        });
        scope.$refresh();
        scope.$emit("showed", index, _oldCursor);
        if (index != _oldCursor) scope.$emit("changed", index, _oldCursor);
        _oldCursor = state.cursor;
    }

    function play(interval) { // 开始播放
        if (!isNaN(interval)) {
            state.interval = parseInt(interval);
        }
        if (!state._playTimer) {
            if (!state._hasEvent) {
                $root.bind("mouseover", pause);
                $root.bind("mouseout", play);
                state._hasEvent = 1;
            }
            state._playTimer = setInterval(state.next.bind(scope), state.interval);
        }
    };

    function pause() { // 暂停播放
        if (state._playTimer) {
            clearInterval(state._playTimer);
            delete state._playTimer;
            if (scope.onStop) {
                scope.onStop.call(scope, state.cursor);
            }
        }
    }
    scope.init = function(widget) {
        scope.$on("pause", pause);
        scope.$on("play", play);
        scope.$on("set", state.set);
        if (!$$.isDefined(state.showhide)) state.showhide = !state.slide;
        roles = widget.roles;
        $root = widget.$root;
        $navs = roles["tab-nav"];
        $bodys = roles["tab-body"];
        state.total = total = $navs ? $navs.length : 0;

        widget.updateRoles(function() { //监听roles变更
            $navs = roles["tab-nav"];
            $bodys = roles["tab-body"];
            state.total = total = $navs ? $navs.length : 0;
            if(state.total && $navs[state.cursor] != state.ctrl){
                state.set(state.cursor);
            }
        });

        state.interval = parseInt(state.interval); // 播放间隔
        var delay = state.delay;

        if (state.events) {
            if (delay) {
                widget.roleDelegate("mouseout", {
                    "tab-nav": function(e) {
                        if (state._delayTimer) {
                            clearTimeout(state._delayTimer);
                            delete state._delayTimer;
                        }
                        return false;
                    }
                });
            }

            state.nav = function(tab) {
                if (!$navs) {
                    widget.updateRoles();
                }
                var i = tab.getAttribute("tab-index");
                if(i){
                    i = getIndex(i);
                    if (state.cursor != i) state.set(i);
                    return false;
                }
                for (i = 0; i < total; i++) {
                    if ($navs[i] == tab) {
                        if (state.cursor != i) state.set(i);
                        return false;
                    }
                }
            }
            widget.roleDelegate(state.events, {
                "tab-nav": function(){
                    if (delay) {
                        if (state._delayTimer) {
                            clearTimeout(state._delayTimer);
                        }
                        state._delayTimer = setTimeout(state.nav.bind(this, this), delay);
                    }else{
                        state.nav(this);
                    }
                }
            });
        }
        
        widget.roleDelegate("click", {
            "tab-prev": function() {
                state.prev();
                return false;
            },
            "tab-next": function() {
                state.next();
                return false;
            },
            "tab-first": function() {
                state.set(0);
                scope.onReset && scope.onReset();
                return false;
            },
            "tab-last": function() {
                state.set(total - 1);
                return false;
            }
        });
        state.interval && play();
        state.set(state.cursor);

        if (state.slide) {
            if (!$$.isNumber(state.slide)) state.slide = 300;
            var k, posObj = function(x) {
                var obj = {};
                var posMethod = 'left';
                obj[posMethod] = x;
                return obj;
            }
            var aniTab = function($p, $n, w){
                $p.animate(posObj(w), aniTime);
                $n.animate(posObj(0), aniTime);
                _show(k);
            };
            var $tabBody = roles["tab-body"];
            var width = $tabBody[0].clientWidth;
            $tabBody.each(function(v, i) {
                if (i == 0) {
                    return;
                }

                $$(v).css(posObj(width))
            });

            scope.$on("showed", function(i, _i) {
                var $nowBody = $tabBody.eq(i);
                var $prevBody = $tabBody.eq(_i);
                $tabBody.each(function(v, j) {
                    if (j == i || j == _i) {
                        return;
                    }
                    if (j < i) {
                        $$(v).css(posObj(-width))
                    } else {
                        $$(v).css(posObj(width))
                    }

                }); //<-- 将小于i的放在左边位置，大于i的放在右边位置，从而左右流畅滑动

                if (i > _i) {
                    $prevBody.animate(posObj(-width), state.slide)
                } else {

                    $prevBody.animate(posObj(width), state.slide)
                }
                $nowBody.animate(posObj(0), state.slide);

            });

            var isSwiping;
            var downTime, downX, downY, i;
            var aniTime = state.slide/2;
            $tabBody.bind('mousedown touchstart', function(e) {
                isSwiping = true;
                downTime = new Date().getTime();
                downX = e.clientX;
                downY = e.clientY;

                $tabBody.each(function(v, j) {
                    if (this.classList.contains('current')) { i = j; }
                });
                scope.$prevBody = $tabBody.eq(i);
                scope.prevLeft = parseInt(scope.$prevBody.css('left'));//store prev left
                var k = i - 1 <= 0 ? 0 : i - 1;
                var l = i + 1 >= ($tabBody.length - 1) ? ($tabBody.length - 1) : i + 1;
                scope.nowLefts = [parseInt($tabBody.eq(k).css('left')), parseInt($tabBody.eq(l).css('left'))]//nowbody is not set
                
            });
            $$(document).bind('mousemove touchmove', function(e) {
                if (isSwiping) {
                    var moveX = e.clientX - downX;
                    var moveY = e.clientY - downY;
                    var direction;

                    if (Math.abs(moveX) >= Math.abs(moveY)) {
                        if (e.clientX - downX < 0) direction = 'left'
                        else direction = 'right'
                    } else {
                        if (e.clientY - downY < 0) direction = 'up'
                        else direction = 'down'
                    }
                    var nowLeft;

                    if (direction == 'right' && !(i == 0)) {
                        k = i - 1;
                        scope.nowLeft = scope.nowLefts[0];
                    } else if (direction == 'left' && !(i == $tabBody.length - 1)) {
                        k = i + 1;
                        scope.nowLeft = scope.nowLefts[1];
                    } else {
                        scope.$nowBody = null;
                        return;
                    }
                    e.preventDefault();
                    scope.$nowBody = $tabBody.eq(k);
                    scope.$nowBody.css({ left: scope.nowLeft + moveX });
                    scope.$prevBody.css({ left:scope.prevLeft+ moveX })
                }
            })
            $$(document).bind('mouseup touchend', function(e) {
                if (!isSwiping) return;
                isSwiping = false;
                var moveTime = (new Date().getTime() - downTime) / 1000;
                var direction;
                var moveX = e.clientX - downX;
                var moveY = e.clientY - downY;
                if (Math.abs(moveX) >= Math.abs(moveY)) {
                    if (e.clientX - downX < 0) direction = 'left'
                    else direction = 'right'
                } else {
                    if (e.clientY - downY < 0) direction = 'up'
                    else direction = 'down'
                }


                if (moveTime < 0.25&&(!(Math.abs(moveX) < 50 && Math.abs(moveY) < 50))) {
                    scope.scroll(direction);  //scroll left or right
                    return;
                }
                
                //pan result deal with
                var tmp = parseInt(scope.$prevBody.css('left'));
                if ((tmp < 0 && Math.abs(tmp) > width / 2) || (tmp > 0 && tmp > width / 2)) {//tmp<0=>left,tmp>0=>right
                    aniTab(scope.$prevBody,scope.$nowBody,tmp>0?width:-width)

                } else {
                    scope.$prevBody.animate(posObj(0), aniTime);  //no change,ani to reset
                    if(scope.$nowBody) scope.$nowBody.animate(posObj(scope.nowLeft), aniTime);
                }
            });

            scope.scroll = function(direction) {
                switch(direction){
                case 'left':
                    if(!(i == $tabBody.length - 1)){
                        aniTab(scope.$prevBody,$tabBody.eq(i+1),-width)
                    }
                    break;
                case 'right':
                    if(!(i == 0)){
                        aniTab(scope.$prevBody,$tabBody.eq(i-1),width)
                    }
                    break;
                case 'none':break;
                default:break;
                }
            };
        }
    }
});
